package com.myk.game.gobangchess.rooms.oldrooms;

import com.myk.game.gobangchess.DataManager;
import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 《康威牌戏》
 * 也就是Domineering，采用10*10+挖对角开局
 */
public class DomineeringRoom extends Room {

    protected int[] firstPoint; //长度为3的数组，row，col，value
    protected int[] secondPoint; //长度为3的数组，row，col，value
    protected List<Sign> tempPointSigns = new ArrayList<>(); //记录最新落点的标记
    protected int boardWidth=9,boardHeight=9; //用于溢出判断、循环上限等

    private static int[][] getDomineeringStyle() {
        //这是某猪调整过的棋盘，经典的Domineering是8*8空秤开局，未来还可以考虑随机开局。
        int[][] iniGrid=new int[][]{
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 9, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0}
        };

        int[] randDir=new int[]{1,2,3,4}; //上下左右
        int[] randMod=new int[]{0,0,0,0}; //奇偶
        int randPos,randTmp;
        for(int i=3;i>0;i--){
            randPos=(int)Math.floor(Math.random()*(i+1));
            randTmp=randDir[i]; randDir[i]=randDir[randPos]; randDir[randPos]=randTmp;
        }
        randPos=(int)Math.floor(Math.random()*4);
        randMod[randPos]=1;
        do{
            randPos=(int)Math.floor(Math.random()*4);
        }while(randMod[randPos]==1);
        randMod[randPos]=1;

        //前两个随机ban在最外圈
        int randX,randY;
        for(int i=0;i<2;i++){
            do {
                switch (randDir[i]) {
                    case 1:
                        randX=0;
                        randY=(int)Math.floor(Math.random()*9);
                        break;
                    case 2:
                        randX=8;
                        randY=(int)Math.floor(Math.random()*9);
                        break;
                    case 3:
                        randX=(int)Math.floor(Math.random()*9);
                        randY=0;
                        break;
                    default: //其实就是case4 要不然warning太烦了
                        randX=(int)Math.floor(Math.random()*9);
                        randY=8;
                }
            }while(((randX+randY)%2!=randMod[i])||(iniGrid[randX][randY]==9));
            iniGrid[randX][randY]=9;
        }

        //第三个在次外圈
        do {
            switch (randDir[2]) {
                case 1:
                    randX=1;
                    randY=(int)Math.floor(Math.random()*7)+1;
                    break;
                case 2:
                    randX=7;
                    randY=(int)Math.floor(Math.random()*7)+1;
                    break;
                case 3:
                    randX=(int)Math.floor(Math.random()*7)+1;
                    randY=1;
                    break;
                default:
                    randX=(int)Math.floor(Math.random()*7)+1;
                    randY=7;
            }
        }while(((randX+randY)%2!=randMod[2]));
        iniGrid[randX][randY]=9;

        //第四个在次内圈
        do {
            switch (randDir[3]) {
                case 1:
                    randX=2;
                    randY=(int)Math.floor(Math.random()*5)+2;
                    break;
                case 2:
                    randX=6;
                    randY=(int)Math.floor(Math.random()*5)+2;
                    break;
                case 3:
                    randX=(int)Math.floor(Math.random()*5)+2;
                    randY=2;
                    break;
                default:
                    randX=(int)Math.floor(Math.random()*5)+2;
                    randY=6;
            }
        }while(((randX+randY)%2!=randMod[3]));
        iniGrid[randX][randY]=9;

        return iniGrid;
    }

    public DomineeringRoom(String roomName) {
        super(roomName, "黑方竖着放，白方横着放，放不下就输。使用某猪调整过的的棋盘。", "康威牌戏", GridsUtils.createEmptyGrids(9,9), true, true);
    }

    @Override
    public String getRuleText() {
        return "[玩法]\n" +
                "黑先，每回合落两子，且必须竖向相邻。\n" +
                "白后，每回合落两子，且必须横向相邻。\n" +
                "无法落子判负。\n" +
                "注：棋盘生成的具体算法比较复杂，故不详述。\n";
    }

    @Override
    protected void onStartPrepare() {
        curGrids = getDomineeringStyle();
        noticeBlackMove();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        firstPoint = null;
        secondPoint = null;
        tempPointSigns.clear();
    }

    @Override
    public void doRule(int row, int col, int value) {
        if(curGrids[row][col]!=0){
            return;
        }
        if (firstPoint == null) {
            if(!canMoveFirst(row,col,cur)){ //增加了第一步前的判断
                return;
            }
            curGrids[row][col] = value + 10; //用方形棋子
            firstPoint = new int[]{row, col, value};
            updateTempPointSigns();
            noticeAllRefreshGameInfo();
        }else {
            if( (cur==1 && ((row==firstPoint[0]-1)||(row==firstPoint[0]+1)) && col==firstPoint[1]) ||
                (cur==2 && row==firstPoint[0] && ((col==firstPoint[1]-1)||(col==firstPoint[1]+1))) ){ 
            //每回合的第二步必须横向(黑)或竖向(白)相邻
                curGrids[row][col] = value + 10;
                secondPoint = new int[]{row, col, value};
                updateTempPointSigns();
                stepAdd();
                WinState winState = checkWin();
                if (winState != null) {
                    firstPoint = null; //用于解决一个奇怪的BUG
                    doOver(winState.winMode, winState.winMsg);
                } else {
                    noticeChangeMove();
                }
            }
        }
    }

        //切换行动方
    protected void noticeChangeMove() {
        firstPoint = null;
        secondPoint = null;
        if (cur == 1) {
            noticeWhiteMove();
        }
        else if (cur == 2) {
            noticeBlackMove();
        }
    }

    protected boolean canMoveFirst(int row,int col,int player){
        //判断第一步能不能走（即落在这里第二步有没有合法走法）
        if(curGrids[row][col]!=0){
            return false;
        }
        boolean flagCanMove=false;
        if(player==1){
            if(row>0 && curGrids[row-1][col]==0){
                flagCanMove=true;
            }
            if(row<boardWidth-1 && curGrids[row+1][col]==0){
                flagCanMove=true;
            }
        }else{
            if(col>0 && curGrids[row][col-1]==0){
                flagCanMove=true;
            }
            if(col<boardHeight-1 && curGrids[row][col+1]==0){
                flagCanMove=true;
            }
        }
        return flagCanMove;
    }


    protected WinState checkWin(){//int state) {
        boolean canMove = false;
        for(int i=0;i<boardWidth;i++){
            for(int j=0;j<boardHeight;j++){
                if(canMoveFirst(i,j,3-cur)){
                    canMove=true;
                    break;
                }
            }
            if(canMove){
                break;
            }
        }

        if (!canMove) {
            if (cur == 1) {
                return new WinState(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
            } else {
                return new WinState(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
            }
        }else{
            return null;
        }
    }

    @Override
    public String getGameInfo() {
        signList.clear();


        if (firstPoint != null) { //把第二步可以落子的地方高亮出来
            int row=firstPoint[0],col=firstPoint[1];
            List<Integer> indexes = new ArrayList<Integer>();
            if (cur == 1) {
                if(row<boardWidth-1 && curGrids[row+1][col] == 0){
                    indexes.add(getIndex(row+1, col));
                }
                if(row>0 && curGrids[row-1][col] == 0){
                    indexes.add(getIndex(row-1, col));
                }
            }else{
                if(col<boardHeight-1 && curGrids[row][col+1] == 0){
                    indexes.add(getIndex(row,col+1));
                }
                if(col>0 && curGrids[row][col-1] == 0){
                    indexes.add(getIndex(row, col-1));
                }
            }
            if (!indexes.isEmpty()){
                signList.add(new AroundSign(indexes, "#449F80F7", "#FF9F80F7", 1.2f));
            }
        }

        signList.addAll(tempPointSigns);
        return super.getGameInfo();
    }

    protected int getJudgeLength(int x, int y, int dx, int dy) {
        int value = curGrids[x][y];
        int length = 0;
        while (isInGrids(x, y)) {
            if (curGrids[x][y] != value) {
                return length;
            }
            length++;
            x += dx;
            y += dy;
        }
        return length;
    }

    // 判断位置在棋盘上
    protected boolean isInGrids(int row, int col) {
        return row >= 0 && row <= curGrids.length - 1 && col >= 0 && col <= curGrids[0].length - 1;
    }

    public static class WinState{
        public int winMode;
        public String winMsg;

        public WinState(int winMode, String winMsg) {
            this.winMode = winMode;
            this.winMsg = winMsg;
        }

    }

    protected void updateTempPointSigns(){
        tempPointSigns.clear();
        //新落子提示
        if (secondPoint != null) {
            tempPointSigns.add(new GroundSign(getIndex(secondPoint[0], secondPoint[1]), "#00000000", ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        }
        if (firstPoint != null) {
            tempPointSigns.add(new GroundSign(getIndex(firstPoint[0], firstPoint[1]), "#00000000", ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        }
    }
}